home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / png / pngcheck / pngcheck.c < prev   
C/C++ Source or Header  |  1995-03-27  |  8KB  |  302 lines

  1. /*
  2.  * authenticate a PNG file (as per draft 9)
  3.  *
  4.  * this program checks the PNG identifier with conversion checks,
  5.  * the file structure and the chunk CRCs.
  6.  *
  7.  * With -v switch, the chunk names are printed.
  8.  * with -t switch, text chunks are printed (without any charset conversion)
  9.  *
  10.  * written by Alexander Lehmann <alex@hal.rhein-main.de>
  11.  *
  12.  *
  13.  * 23.02.95 fixed wrong magic numbers
  14.  *
  15.  * 13.03.95 crc code from png spec, compiles on memory impaired PCs now,
  16.  *          check for IHDR/IEND chunks
  17.  *
  18.  * 23 Mar 95  glennrp rewrote magic number checking and moved it to
  19.  *             PNG_check_magic(buffer)
  20.  *
  21.  * 27.03.95 AL: fixed CRC code for 64 bit, -t switch, unsigned char vs. char
  22.  *          pointer changes
  23.  *
  24.  *
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <ctype.h>
  31.  
  32. int PNG_check_magic(unsigned char *magic);
  33. int PNG_check_chunk_name(char *chunk_name);
  34.  
  35. #define BS 32000 /* size of read block for CRC calculation */
  36. int verbose; /* ==1 print chunk info */
  37. int printtext; /* ==1 print tEXt chunks */
  38. char *fname;
  39. unsigned char buffer[BS];
  40.  
  41. /* table of crc's of all 8-bit messages */
  42. unsigned long crc_table[256];
  43.  
  44. /* Flag: has the table been computed? Initially false. */
  45. int crc_table_computed = 0; 
  46.  
  47. /* make the table for a fast crc */
  48. void make_crc_table(void)
  49. {
  50.   unsigned long c;
  51.   int n, k;
  52.  
  53.   for (n = 0; n < 256; n++)
  54.   {
  55.     c = (unsigned long)n;
  56.     for (k = 0; k < 8; k++)
  57.       c = c & 1 ? 0xedb88320L ^ (c >> 1) : c >> 1;
  58.     crc_table[n] = c;
  59.   }
  60.   crc_table_computed = 1;
  61. }
  62.  
  63. /* update a running crc with the bytes buf[0..len-1]--the crc should be
  64.    initialized to all 1's, and the transmitted value is the 1's complement
  65.    of the final running crc. */
  66.  
  67. unsigned long update_crc(unsigned long crc, unsigned char *buf, int len)
  68. {
  69.   unsigned long c = crc;
  70.   unsigned char *p = buf;
  71.   int n = len;
  72.  
  73.   if (!crc_table_computed) {
  74.     make_crc_table();
  75.   } 
  76.   if (n > 0) do {
  77.     c = crc_table[(c ^ (*p++)) & 0xff] ^ (c >> 8);
  78.   } while (--n);
  79.   return c;
  80. }
  81.  
  82. /* use these instead of ~crc and -1, since that doesn't work on machines that
  83.    have 64 bit longs */
  84.  
  85. #define CRCCOMPL(c) ((c)^0xffffffff)
  86. #define CRCINIT (CRCCOMPL(0))
  87.  
  88. unsigned long getlong(FILE *fp)
  89. {
  90.   unsigned long res=0;
  91.   int c;
  92.   int i;
  93.  
  94.   for(i=0;i<4;i++) {
  95.     if((c=fgetc(fp))==EOF) {
  96.       printf("%s: EOF while reading 4 bytes value\n", fname);
  97.       return 0;
  98.     }
  99.     res<<=8;
  100.     res|=c&0xff;
  101.   }
  102.   return res;
  103. }
  104.  
  105. void pngcheck(FILE *fp, char *_fname)
  106. {
  107.   long s;
  108.   unsigned char magic[8];
  109.   char chunkid[5];
  110.   int toread;
  111.   int c;
  112.   unsigned long crc, filecrc;
  113.   int first=1;
  114.  
  115.   fname=_fname; /* make filename available to functions above */
  116.  
  117.   if(fread(magic, 1, 8, fp)!=8) {
  118.     printf("%s: Cannot read PNG header\n", fname);
  119.     return;
  120.   }
  121.  
  122.   if (PNG_check_magic(magic) != 0) return;
  123.  
  124.   while((c=fgetc(fp))!=EOF) {
  125.     ungetc(c, fp);
  126.     s=getlong(fp);
  127.     if(fread(chunkid, 1, 4, fp)!=4) {
  128.       printf("%s: EOF while reading chunk type\n", fname);
  129.       return;
  130.     }
  131.  
  132.     chunkid[4]=0;
  133.  
  134.     if (PNG_check_chunk_name(chunkid) != 0) return;
  135.  
  136.     if(verbose) {
  137.       printf("%s: chunk %s at %lx length %lx\n", fname, chunkid, ftell(fp)-4, s);
  138.     }
  139.  
  140.     if(first && strcmp(chunkid,"IHDR")!=0) {
  141.       printf("%s: file doesn't start with a IHDR chunk\n", fname);
  142.     }
  143.     first=0;
  144.  
  145.     crc=update_crc(CRCINIT, (unsigned char *)chunkid, 4);
  146.  
  147.     while(s>0) {
  148.       toread=s;
  149.       if(toread>BS) {
  150.         toread=BS;
  151.       }
  152.       if(fread(buffer, 1, toread, fp)!=toread) {
  153.         printf("%s: EOF while reading chunk data (%s)\n", fname, magic);
  154.     return;
  155.       }
  156.       crc=update_crc(crc, buffer, toread);
  157.       s-=toread;
  158.       if(printtext && strcmp(chunkid, "tEXt")==0) {
  159.         if(strlen((char *)buffer)<toread) {
  160.           buffer[strlen((char *)buffer)]=':';
  161.     }
  162.         fwrite(buffer, 1, toread, stdout);
  163.       }
  164.     }
  165.     if(printtext && strcmp(chunkid, "tEXt")==0) {
  166.       printf("\n");
  167.     }
  168.     filecrc=getlong(fp);
  169.     if(filecrc!=CRCCOMPL(crc)) {
  170.       printf("%s: CRC error in chunk %s (actual %08lx, should be %08lx)\n",
  171.               fname, chunkid, CRCCOMPL(crc), filecrc);
  172.       return;
  173.     }
  174.   }
  175.   if(strcmp(chunkid, "IEND")!=0) {
  176.     printf("%s: file doesn't end with a IEND chunk\n", fname);
  177.     return;
  178.   }
  179.   printf("%s: file appears to be OK\n", fname);
  180. }
  181.  
  182. int main(int argc, char *argv[])
  183. {
  184.   FILE *fp;
  185.   int i;
  186.  
  187.   if(argc>1 && strcmp(argv[1],"-v")==0) {
  188.     verbose=1;
  189.     argc--;
  190.     argv++;
  191.   } else
  192.   if(argc>1 && strcmp(argv[1],"-t")==0) {
  193.     printtext=1;
  194.     argc--;
  195.     argv++;
  196.   }
  197.  
  198.   if(argc==1) {
  199.     pngcheck(stdin, "stdin");
  200.   } else {
  201.     for(i=1;i<argc;i++) {
  202.       if((fp=fopen(argv[i],"rb"))==NULL) {
  203.         perror(argv[i]);
  204.       } else {
  205.         pngcheck(fp, argv[i]);
  206.     fclose(fp);
  207.       }
  208.     }
  209.   }
  210.  
  211.   return 0;
  212. }
  213.  
  214. /*  PNG_subs
  215.  *
  216.  *  Utility routines for PNG encoders and decoders
  217.  *  by Glenn Randers-Pehrson
  218.  *
  219.  */
  220. #include <stdio.h>
  221. #include <sys/types.h>
  222. #include <sys/stat.h>
  223. #include <fcntl.h>
  224.  
  225. #define OK      0
  226. #define ERROR   -1
  227. #define WARNING -2
  228.  
  229. /* (int)PNG_check_magic ((unsigned char*) magic)
  230.  *
  231.  * check the magic numbers in 8-byte buffer at the beginning of
  232.  * a PNG file.
  233.  *
  234.  * by Alexander Lehmann and Glenn Randers-Pehrson
  235.  *
  236.  * This is free software; you can redistribute it and/or modify it 
  237.  * without any restrictions.
  238.  *
  239.  */
  240.  
  241. int PNG_check_magic(unsigned char *magic)
  242. {
  243.     if (strncmp((char *)&magic[1],"PNG",3) != 0) {
  244.              fprintf(stderr, "not a PNG file\n");
  245.          return(ERROR);
  246.             }
  247.  
  248.     if (magic[0] != 0x89 ||
  249.          strncmp((char *)&magic[4],"\015\012\032\012",4) != 0) {
  250.          fprintf(stderr, "PNG file is CORRUPTED.\n");
  251.  
  252.          /* this coding taken from Alexander Lehmanns checkpng code   */
  253.  
  254.         if(strncmp((char *)&magic[4],"\n\032",2) == 0) fprintf
  255.              (stderr," It seems to have suffered DOS->unix conversion\n");
  256.         else
  257.         if(strncmp((char *)&magic[4],"\r\032",2) == 0) fprintf
  258.              (stderr," It seems to have suffered DOS->Mac conversion\n");
  259.         else
  260.         if(strncmp((char *)&magic[4],"\r\r\032",3) == 0) fprintf
  261.              (stderr," It seems to have suffered unix->Mac conversion\n");
  262.         else
  263.         if(strncmp((char *)&magic[4],"\n\n\032",3) == 0) fprintf
  264.              (stderr," It seems to have suffered Mac-unix conversion\n");
  265.         else
  266.         if(strncmp((char *)&magic[4],"\r\n\032\r",4) == 0) fprintf
  267.              (stderr," It seems to have suffered unix->DOS conversion\n");
  268.         else
  269.         if(strncmp((char *)&magic[4],"\r\r\n\032",4) == 0) fprintf
  270.              (stderr," It seems to have suffered unix->DOS conversion\n");
  271.         else
  272.         if(strncmp((char *)&magic[4],"\r\n\032\n",4) != 0) fprintf
  273.              (stderr," It seems to have suffered EOL conversion\n");
  274.  
  275.         if(magic[0]==9) fprintf
  276.              (stderr," It was probably transmitted through a 7bit channel\n");
  277.         else
  278.         if(magic[0]!=0x89) fprintf
  279.              (stderr,"  It was probably transmitted in text mode\n");
  280.         /*  end of Alexander Lehmann's code  */
  281.         return(ERROR);
  282.         }
  283.     return (OK);
  284. }
  285.  
  286. /* (int)PNG_check_magic ((char*) magic)
  287.  *
  288.  * from Alex Lehmann 
  289.  *
  290.  */
  291.  
  292. int PNG_check_chunk_name(char *chunk_name)
  293. {
  294.      if(!isalpha(chunk_name[0]) || !isalpha(chunk_name[1]) ||
  295.         !isalpha(chunk_name[2]) || !isalpha(chunk_name[3])) {
  296.          printf("chunk name %02x %02x %02x %02x doesn't comply to naming rules\n",
  297.          chunk_name[0],chunk_name[1],chunk_name[2],chunk_name[3]);
  298.          return (ERROR);
  299.          }
  300.      else return (OK);
  301. }
  302.